package com.mkx.bloomfilter;

import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.util.Random;

/**
 * 哈希函数生成器，提供多个独立的哈希函数
 * 实现了基于MurmurHash3算法的哈希函数，具有良好的分布性和性能
 */
public class HashFunctionGenerator implements Serializable {
    private static final long serialVersionUID = 1L;
    
    // 随机数生成器
    private final Random random;
    
    // 哈希种子数组
    private final int[] seeds;
    
    // 哈希函数数量
    private final int hashFunctionCount;
    
    /**
     * 构造函数
     * @param hashFunctionCount 需要的哈希函数数量
     */
    public HashFunctionGenerator(int hashFunctionCount) {
        if (hashFunctionCount <= 0) {
            throw new IllegalArgumentException("Hash function count must be positive");
        }
        
        this.hashFunctionCount = hashFunctionCount;
        this.random = new Random();
        this.seeds = new int[hashFunctionCount];
        
        // 生成不同的种子
        for (int i = 0; i < hashFunctionCount; i++) {
            seeds[i] = random.nextInt();
        }
    }
    
    /**
     * 构造函数，使用指定的种子生成器
     * @param hashFunctionCount 需要的哈希函数数量
     * @param seed 随机数生成器的种子
     */
    public HashFunctionGenerator(int hashFunctionCount, long seed) {
        if (hashFunctionCount <= 0) {
            throw new IllegalArgumentException("Hash function count must be positive");
        }
        
        this.hashFunctionCount = hashFunctionCount;
        this.random = new Random(seed);
        this.seeds = new int[hashFunctionCount];
        
        // 生成不同的种子
        for (int i = 0; i < hashFunctionCount; i++) {
            seeds[i] = random.nextInt();
        }
    }
    
    /**
     * 获取指定索引的哈希函数生成的哈希值
     * @param value 要哈希的值
     * @param index 哈希函数索引
     * @param maxValue 最大哈希值（不包含）
     * @return 哈希值，范围在[0, maxValue)
     */
    public int getHash(Object value, int index, int maxValue) {
        if (index < 0 || index >= hashFunctionCount) {
            throw new IndexOutOfBoundsException("Hash function index out of bounds");
        }
        if (maxValue <= 0) {
            throw new IllegalArgumentException("Max value must be positive");
        }
        
        // 获取对应索引的种子
        int seed = seeds[index];
        
        // 根据值的类型计算哈希
        int hash;
        if (value instanceof String) {
            hash = murmurHash3String((String) value, seed);
        } else if (value instanceof Integer) {
            hash = murmurHash3Int((Integer) value, seed);
        } else if (value instanceof Long) {
            hash = murmurHash3Long((Long) value, seed);
        } else if (value instanceof Double) {
            hash = murmurHash3Double((Double) value, seed);
        } else if (value instanceof Float) {
            hash = murmurHash3Float((Float) value, seed);
        } else if (value instanceof Boolean) {
            hash = ((Boolean) value) ? (seed ^ 0x9E3779B9) : (seed ^ 0x3C6EF372);
        } else if (value instanceof byte[]) {
            hash = murmurHash3((byte[]) value, seed);
        } else {
            // 对于其他类型，使用对象的hashCode并结合种子
            hash = murmurHash3String(value.toString(), seed);
        }
        
        // 确保哈希值为正并在范围内
        return Math.abs(hash) % maxValue;
    }
    
    /**
     * 获取所有哈希函数生成的哈希值数组
     * @param value 要哈希的值
     * @param maxValue 最大哈希值（不包含）
     * @return 哈希值数组
     */
    public int[] getAllHashes(Object value, int maxValue) {
        // 优化：使用两个独立哈希值生成多个哈希值，减少哈希计算次数
        int[] hashes = new int[hashFunctionCount];
        
        // 计算两个基础哈希值
        int h1 = getHash(value, 0x9747B28C, Integer.MAX_VALUE);
        int h2 = getHash(value, 0x6A197D35, Integer.MAX_VALUE);
        
        // 使用双重哈希技术生成多个哈希值
        for (int i = 0; i < hashFunctionCount; i++) {
            hashes[i] = Math.abs(h1 + i * h2) % maxValue;
        }
        return hashes;
    }
    
    /**
     * 直接计算字符串的MurmurHash3，避免额外的字节数组创建
     */
    private int murmurHash3String(String str, int seed) {
        int len = str.length();
        int h1 = seed;
        int c1 = 0xcc9e2d51;
        int c2 = 0x1b873593;
        
        int i = 0;
        // 处理4字节块
        while (i + 3 < len) {
            int k1 = (str.charAt(i) & 0xFF) | 
                     ((str.charAt(i + 1) & 0xFF) << 8) |
                     ((str.charAt(i + 2) & 0xFF) << 16) |
                     ((str.charAt(i + 3) & 0xFF) << 24);
            
            k1 *= c1;
            k1 = Integer.rotateLeft(k1, 15);
            k1 *= c2;
            
            h1 ^= k1;
            h1 = Integer.rotateLeft(h1, 13);
            h1 = h1 * 5 + 0xe6546b64;
            
            i += 4;
        }
        
        // 处理剩余字节
        int k1 = 0;
        switch (len - i) {
            case 3:
                k1 ^= (str.charAt(i + 2) & 0xFF) << 16;
            case 2:
                k1 ^= (str.charAt(i + 1) & 0xFF) << 8;
            case 1:
                k1 ^= (str.charAt(i) & 0xFF);
                k1 *= c1;
                k1 = Integer.rotateLeft(k1, 15);
                k1 *= c2;
                h1 ^= k1;
        }
        
        // 最终混合
        h1 ^= len;
        h1 = fmix32(h1);
        
        return h1;
    }
    
    /**
     * 直接计算整数的MurmurHash3
     */
    private int murmurHash3Int(int value, int seed) {
        int h1 = seed;
        int k1 = value;
        int c1 = 0xcc9e2d51;
        int c2 = 0x1b873593;
        
        k1 *= c1;
        k1 = Integer.rotateLeft(k1, 15);
        k1 *= c2;
        
        h1 ^= k1;
        h1 = Integer.rotateLeft(h1, 13);
        h1 = h1 * 5 + 0xe6546b64;
        
        h1 ^= 4;  // 整数的长度是4字节
        h1 = fmix32(h1);
        
        return h1;
    }
    
    /**
     * 直接计算长整型的MurmurHash3
     */
    private int murmurHash3Long(long value, int seed) {
        int h1 = seed;
        int c1 = 0xcc9e2d51;
        int c2 = 0x1b873593;
        
        // 处理低32位
        int k1 = (int) value;
        k1 *= c1;
        k1 = Integer.rotateLeft(k1, 15);
        k1 *= c2;
        
        h1 ^= k1;
        h1 = Integer.rotateLeft(h1, 13);
        h1 = h1 * 5 + 0xe6546b64;
        
        // 处理高32位
        k1 = (int) (value >>> 32);
        k1 *= c1;
        k1 = Integer.rotateLeft(k1, 15);
        k1 *= c2;
        
        h1 ^= k1;
        h1 = Integer.rotateLeft(h1, 13);
        h1 = h1 * 5 + 0xe6546b64;
        
        h1 ^= 8;  // 长整型的长度是8字节
        h1 = fmix32(h1);
        
        return h1;
    }
    
    /**
     * 计算双精度浮点数的MurmurHash3
     */
    private int murmurHash3Double(double value, int seed) {
        return murmurHash3Long(Double.doubleToRawLongBits(value), seed);
    }
    
    /**
     * 计算单精度浮点数的MurmurHash3
     */
    private int murmurHash3Float(float value, int seed) {
        return murmurHash3Int(Float.floatToRawIntBits(value), seed);
    }
    
    /**
     * MurmurHash3算法实现（32位版本）- 优化版本
     * 该算法具有良好的分布性和雪崩效应
     * @param data 输入数据
     * @param seed 种子值
     * @return 32位哈希值
     */
    private int murmurHash3(byte[] data, int seed) {
        final int c1 = 0xcc9e2d51;
        final int c2 = 0x1b873593;
        final int r1 = 15;
        final int r2 = 13;
        final int m = 5;
        final int n = 0xe6546b64;
        
        int hash = seed;
        int len = data.length;
        int i = 0;
        
        // 处理4字节的块 - 优化循环性能
        while (len >= 4) {
            // 优化字节转换为整数的过程
            int k = (data[i] & 0xFF);
            k |= (data[i + 1] & 0xFF) << 8;
            k |= (data[i + 2] & 0xFF) << 16;
            k |= (data[i + 3] & 0xFF) << 24;
            
            k *= c1;
            k = Integer.rotateLeft(k, r1);
            k *= c2;
            
            hash ^= k;
            hash = Integer.rotateLeft(hash, r2) * m + n;
            
            i += 4;
            len -= 4;
        }
        
        // 处理剩余的字节
        int k1 = 0;
        switch (len) {
            case 3:
                k1 |= (data[i + 2] & 0xFF) << 16;
            case 2:
                k1 |= (data[i + 1] & 0xFF) << 8;
            case 1:
                k1 |= (data[i] & 0xFF);
                k1 *= c1;
                k1 = Integer.rotateLeft(k1, r1);
                k1 *= c2;
                hash ^= k1;
        }
        
        // 最终混合
        hash ^= data.length;
        hash = fmix32(hash);
        
        return hash;
    }
    
    /**
     * MurmurHash3的最终混合函数
     * @param h 输入哈希值
     * @return 混合后的哈希值
     */
    private int fmix32(int h) {
        h ^= h >>> 16;
        h *= 0x85ebca6b;
        h ^= h >>> 13;
        h *= 0xc2b2ae35;
        h ^= h >>> 16;
        
        return h;
    }
    
    /**
     * 将整数转换为字节数组
     * @param value 整数
     * @return 字节数组
     */
    private byte[] intToBytes(int value) {
        return new byte[] {
            (byte) (value >>> 24),
            (byte) (value >>> 16),
            (byte) (value >>> 8),
            (byte) value
        };
    }
    
    /**
     * 获取哈希函数数量
     * @return 哈希函数数量
     */
    public int getHashFunctionCount() {
        return hashFunctionCount;
    }
}